﻿// MIT License
// 开源地址：https://gitee.com/co1024/AbcMvc
// Copyright (c) 2021-2023 1024
// Abc.Mvc=Furion+EF+SqlSugar+Pear layui admin.

namespace Abc.Core;

public class SysCacheService : ISysCacheService, ITransient
{
    private readonly ILogger<SysCacheService> _logger;
    private readonly ISqlSugarClient _db;

    public SysCacheService(ILogger<SysCacheService> logger
    , ISqlSugarClient db)
    {
        _logger = logger;
        _db = db;
    }

    /// <summary>
    /// 刷新缓存
    /// </summary>
    /// <param name="type">缓存类型</param>
    /// <returns></returns>
    public async Task<dynamic> RefreshCache(string type = "")
    {
        if (string.IsNullOrWhiteSpace(type))
        {
            await GetListByRoleAsync(true);
            await GetListAsync<SysMenu>(true);
            await GetListAsync<SysDataConfig>(true);

            await GetListAsync<SysEmailSendConfig>(true);
        }
        switch (type)
        {
            case "Menu": await GetListAsync<SysMenu>(true); break;
            case "DataConfig": await GetListAsync<SysDataConfig>(true); break;
            case "Role": await GetListByRoleAsync(true); break;
            case "EmailSendConfig": await GetListAsync<SysEmailSendConfig>(true); break;//邮件发送设置

            default:
                break;
        }

        return new { Succeeded = true, Errors = "刷新成功" };
    }

    /// <summary>
    /// 获取 实体的全部数据
    /// </summary>
    /// <typeparam name="TEntity">数据库表</typeparam>
    /// <returns></returns>
    public async Task<List<TEntity>> GetListAsync<TEntity>(bool isRefresh = false)
        where TEntity : class, new()
    {
        (bool state, List<TEntity> list) result = await GetListCacheAsync<TEntity>(isRefresh);
        if (result.state == true) return result.list;
        //从数据库中读取数据
        return await _db.Queryable<TEntity>().WithCache().ToListAsync();
    }

    /// <summary>
    /// 获取缓存
    /// </summary>
    /// <typeparam name="TEntity">实体</typeparam>
    /// <param name="isRefresh">是否刷新，刷新的话会移除缓存</param>
    /// <returns></returns>
    private async Task<(bool, List<TEntity>)> GetListCacheAsync<TEntity>(bool isRefresh = false)
    {
        if (isRefresh)
        {
            Caches.Remove(Caches.GetTableCacheKey<TEntity>());
        }
        else
        {
            //判断缓存中是否存在，存在直接返回
            var list = await Caches.GetAsync<List<TEntity>>(Caches.GetTableCacheKey<TEntity>());
            if (list != null && list.Any())
            {
                return (true, list);
            }
        }
        return (false, null);
    }

    #region menu

    /// <summary>
    /// 获取后台左侧菜单列表
    /// </summary>
    /// <param name="area">区域</param>
    /// <returns></returns>
    public async Task<List<PearMenuItemOut>> GetPearMenus(string area)
    {
        var entities = await GetListAsync<SysMenu>();
        var dbmenus = entities
           .Where(o => o.IsEnable && o.IsShow)
           .Adapt<List<PearMenuItem>>();
        var rmenus = dbmenus.GetMenus(pid: area);
        return rmenus;
    }

    /// <summary>
    /// 获取菜单列表
    /// </summary>
    /// <param name="area">区域</param>
    /// <returns></returns>
    public async Task<List<SysMenu>> GetMenus(string area = "")
    {
        var entities = await GetListAsync<SysMenu>();
        if (string.IsNullOrWhiteSpace(area))
        {
            return entities;
        }
        else
        {
            var menus = entities
        .Where(o => o.Area != null && o.Area.Trim() == area?.Trim())
        .ToList();
            return menus;
        }
    }

    /// <summary>
    /// 获取用户的菜单
    /// </summary>
    /// <param name="userid"></param>
    /// <returns></returns>
    public async Task<List<SysMenu>> GetMenusByUserId(long userid)
    {
        var roldids = await _db.Queryable<SysUserRole>()
            .Where(o => o.UserId == userid)
            .ToListAsync(o => o.RoleId);
        var menuids = await _db.Queryable<SysRoleMenu>()
            .Where(o => roldids.Contains(o.RoleId))
            .ToListAsync(o => o.MenuId);

        var menus = await GetMenus();

        return menus.Where(o => menuids.Contains(o.Id)).ToList();
    }

    #endregion menu

    #region DataConfig

    /// <summary>
    /// 获取系统设置
    /// </summary>
    /// <returns></returns>
    public async Task<TEntity> GetSetting<TEntity>(string pkey) where TEntity : new()
    {
        var entities = await GetListAsync<SysDataConfig>();
        var settings = await entities.Where(o => o.PKey == pkey).ToListAsync();
        var settingdto = new TEntity();
        foreach (var setting in settings)
        {
            settingdto.FieldSetValue(setting.Key, setting.Value);
        }
        return settingdto;
    }

    /// <summary>
    /// 查询指定父级的所有下级
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="pkey">父级key</param>
    /// <returns></returns>
    public async Task<List<TEntity>> GetDataConfigEntitiesByPKey<TEntity>(string pkey)
    {
        var entities = await GetListAsync<SysDataConfig>();
        var returnentities = entities.Where(o => !string.IsNullOrWhiteSpace(pkey) && o.PKey == pkey).Adapt<List<TEntity>>();
        return returnentities;
    }

    /// <summary>
    /// 获取数据配置
    /// </summary>
    /// <param name="key"></param>
    /// <param name="pkey"></param>
    /// <returns></returns>
    public async Task<TEntity> GetDataConfigByKey<TEntity>(string key, string pkey)
    {
        var entities = await GetListAsync<SysDataConfig>();
        var returnentitie = entities.FirstOrDefault(o => !string.IsNullOrWhiteSpace(pkey) && !string.IsNullOrWhiteSpace(key) && o.PKey == pkey && o.Key == key);
        if (returnentitie == null) return default(TEntity);
        return returnentitie.Adapt<TEntity>();
    }

    /// <summary>
    /// 查询一条
    /// </summary>
    /// <param name="id">ID</param>
    public async Task<TEntity> GetDataConfig<TEntity>(long id)
    {
        var dbentity = await GetListAsync<SysDataConfig>();
        if (dbentity == null) return default(TEntity);
        return dbentity.Adapt<TEntity>();
    }

    /// <summary>
    /// 根据父ID 返回集合
    /// </summary>
    /// <param name="pid"></param>
    /// <returns></returns>
    public async Task<List<SysDataConfig>> GetDataConfigs(long pid)
    {
        var entities = await GetListAsync<SysDataConfig>();
        return await entities.Where(o => o.PId == pid).ToListAsync();
    }

    /// <summary>
    /// 根据分组 返回集合
    /// </summary>
    /// <param name="groupname"></param>
    /// <returns></returns>
    public async Task<List<SysDataConfig>> GetDataConfigs(string groupname)
    {
        var entities = await GetListAsync<SysDataConfig>();
        return await entities.Where(o => o.GroupName != null && o.GroupName.ToLower().Trim() == groupname.ToLower().Trim()).ToListAsync();
    }

    /// <summary>
    /// 获取父级
    /// </summary>
    /// <param name="groupname">分组</param>
    /// <param name="parentkey">父级Key</param>
    /// <returns></returns>
    public async Task<SysDataConfig> GetParentDataConfig(string groupname, string parentkey)
    {
        var entities = await GetListAsync<SysDataConfig>();
        var entity = await entities.FirstOrDefaultAsync(o => o.GroupName != null && o.Key != null && o.GroupName.Trim().ToLower() == groupname.Trim().ToLower() && o.Key.Trim().ToLower() == parentkey.Trim().ToLower());
        return entity;
    }

    /// <summary>
    /// 获取 子集 DataConfig
    /// </summary>
    /// <param name="groupname">分组</param>
    /// <param name="childkey">子级Key</param>
    /// <returns></returns>
    public async Task<List<SysDataConfig>> GetChildDataConfigs(string groupname, string childkey)
    {
        var entities = await GetListAsync<SysDataConfig>();
        var pdc = await entities.FirstOrDefaultAsync(o => o.GroupName != null && o.Key != null && o.GroupName.Trim().ToLower() == groupname.Trim().ToLower() && o.Key.Trim().ToLower() == groupname.Trim().ToLower());
        var dcs = await entities
            .Where(o => o.PId == pdc.Id && o.Key != null && o.Key.Trim().ToLower() == childkey.Trim().ToLower()).ToListAsync();
        return dcs;
    }

    /// <summary>
    /// 获取 子集 DataConfig
    /// </summary>
    /// <param name="groupname">分组</param>
    /// <returns></returns>
    public async Task<List<SysDataConfig>> GetChildDataConfigs(string groupname)
    {
        var entities = await GetListAsync<SysDataConfig>();
        var pdc = await entities.FirstOrDefaultAsync(o => o.GroupName != null && o.Key != null && o.GroupName.Trim().ToLower() == groupname.Trim().ToLower() && o.Key.Trim().ToLower() == groupname.Trim().ToLower());
        var dcs = await entities.Where(o => o.PId == pdc.Id).ToListAsync();
        return dcs;
    }

    /// <summary>
    /// 获取 子集 DataConfig
    /// </summary>
    /// <param name="groupname">分组</param>
    /// <param name="childkey">子级Key</param>
    /// <returns></returns>
    public async Task<SysDataConfig> GetChildDataConfig(string groupname, string childkey)
    {
        var entities = await GetListAsync<SysDataConfig>();
        if (string.IsNullOrWhiteSpace(groupname) || string.IsNullOrWhiteSpace(childkey))
        {
            return null;
        }
        var pdc = await entities.FirstOrDefaultAsync(o => o.GroupName != null && o.Key != null && o.GroupName.Trim().ToLower() == groupname.Trim().ToLower() && o.Key.Trim().ToLower() == groupname.Trim().ToLower());
        var dc = await entities
            .Where(o => o.PId == pdc.Id)
            .FirstOrDefaultAsync(o => o.Key != null && o.Key.Trim().ToLower() == childkey.Trim().ToLower());
        return dc;
    }

    /// <summary>
    /// 获取 子集 DataConfig
    /// </summary>
    /// <param name="groupname">分组</param>
    /// <param name="parentkey">父级Key</param>
    /// <param name="childkey">子级Key</param>
    /// <returns></returns>
    public async Task<SysDataConfig> GetChildDataConfig(string groupname, string parentkey, string childkey)
    {
        var entities = await GetListAsync<SysDataConfig>();
        var pdc = await entities.FirstOrDefaultAsync(o => o.GroupName != null && o.Key != null && o.GroupName.Trim().ToLower() == groupname.Trim().ToLower() && o.Key.Trim().ToLower() == parentkey.Trim().ToLower());
        var dc = await entities
            .Where(o => o.PId == pdc.Id)
            .FirstOrDefaultAsync(o => o.Key != null && o.Key.Trim().ToLower() == childkey.Trim().ToLower());
        return dc;
    }

    #endregion DataConfig

    #region Role

    /// <summary>
    /// 获取角色列表或获取并刷新
    /// </summary>
    /// <param name="isRefresh"></param>
    /// <returns></returns>
    public async Task<List<SysRole>> GetListByRoleAsync(bool isRefresh = false)
    {
        (bool state, List<SysRole> list) result = await GetListCacheAsync<SysRole>(isRefresh);
        if (result.state == true) return result.list;

        var entities = await _db.Queryable<SysRole>()
            .WithCache().ToListAsync();
        return entities;
    }

    #endregion Role

    #region User  不用

    ///// <summary>
    ///// 缓存所有管理员
    ///// </summary>
    ///// <returns></returns>
    //public async Task<List<SysUser>> GetListByUserAsync(bool isRefresh = false)
    //{
    //    (bool state, List<SysUser> list) result = await GetListCacheAsync<SysUser>(isRefresh);
    //    if (result.state == true) return result.list;

    //    var entities = await _dataConfigRepository.Change<SysUser>().DetachedEntities
    //     .Include(o => o.Roles).ThenInclude(o => o.Menus)
    //     .ToListWithCacheAsync();
    //    return entities;
    //}

    #endregion User  不用

    #region 管理用户登陆

    /// <summary>
    /// 获取登陆的管理员用户
    /// </summary>
    /// <param name="userid"></param>
    /// <returns></returns>
    private async Task<SysUser> GetLoginAdminUser(long userid)
    {
        var entity = await _db.Queryable<SysUser>()
           .Includes(o => o.Roles)
           //.ThenInclude(o => o.Menus)
           .FirstAsync(o => o.Id == userid);
        return entity;
    }

    /// <summary>
    /// 获取登陆的管理员用户
    /// </summary>
    /// <returns></returns>
    public async Task<SysUser> GetLoginAdminUser()
    {
        var userid = App.HttpContext.GetLoginUserId();
        if (userid > 0)
        {
            var user = await Caches.GetAsync<SysUser>(Caches.GetCacheKey($"User_{userid}"));
            if (user != null) return user;
            user = await GetLoginAdminUser(userid);
            if (user == null)
            {
                await App.HttpContext?.SignOutAsync(AuthorizeType.AdminAuthenticationScheme);
            }
            return user;
        }
        else
        {
            return default(SysUser);
        }
    }

    /// <summary>
    /// 刷新登陆管理用户缓存
    /// </summary>
    /// <param name="userid"></param>
    /// <returns></returns>
    public async Task RefreshLoginAdminUserCache(long userid)
    {
        // var entities = await GetListByUserAsync();
        var entity = await GetLoginAdminUser(userid);

        //判断下是否有此用户的缓存，有才设置
        var user = await Caches.GetAsync<SysUser>(Caches.GetCacheKey($"User_{userid}"));
        if (user == null) return;

        await SetLoginAdminUserCache(entity);
    }

    /// <summary>
    /// 移除登陆管理用户缓存
    /// </summary>
    /// <param name="userids"></param>
    /// <returns></returns>
    public async Task RemoveLoginAdminUserCache(List<long> userids)
    {
        foreach (var userid in userids)
        {
            await RemoveLoginAdminUserCache(userid);
        }
    }

    /// <summary>
    /// 移除登陆管理用户缓存
    /// </summary>
    /// <param name="userid"></param>
    /// <returns></returns>
    public async Task RemoveLoginAdminUserCache(long userid)
    {
        await Caches.RemoveAsync(Caches.GetCacheKey($"User_{userid}"));
    }

    /// <summary>
    /// 设置登陆管理用户缓存
    /// </summary>
    /// <param name="user"></param>
    /// <returns></returns>
    public async Task SetLoginAdminUserCache(SysUser user)
    {
        if (user == null) return;
        var loginuser = await GetLoginAdminUser(user.Id);
        await loginuser.SetCacheAsync(Caches.GetCacheKey($"User_{user.Id}"), options: new Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions()
        {
            SlidingExpiration = TimeSpan.FromMinutes(30),//滑动过期时间
        });
    }

    /// <summary>
    /// 设置登陆管理用户缓存
    /// </summary>
    /// <param name="userId"></param>
    /// <returns></returns>
    public async Task SetLoginAdminUserCache(long userId)
    {
        var loginuser = await GetLoginAdminUser(userId);
        await loginuser.SetCacheAsync(Caches.GetCacheKey($"User_{loginuser.Id}"), options: new Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions()
        {
            SlidingExpiration = TimeSpan.FromMinutes(30),//滑动过期时间
        });
    }

    /// <summary>
    /// 验证权限
    /// </summary>
    /// <param name="controller"></param>
    /// <param name="action"></param>
    /// <param name="userid"></param>
    /// <param name="menuAreaType">菜单区域类型，MVC和API，默认MVC，</param>
    /// <param name="area">区域，默认HtAdmin，如果是API，默认就是 API</param>
    /// <returns></returns>
    public async Task<bool> HasAuthorize(string controller, string action, long userid = 0, MenuAreaType menuAreaType = MenuAreaType.Mvc, string area = "HtAdmin")
    {
        if (userid <= 0) userid = App.HttpContext.GetLoginUserId();
        var user = await Caches.GetAsync<SysUser>(Caches.GetCacheKey($"User_{userid}"));
        if (user == null)
        {
            //var context = App.GetService<IHttpContextAccessor>();
            //var a = context.GetCookiesValue<long>($"User_{userid}");
            // var entities = await GetListByUserAsync();
            user = await GetLoginAdminUser(userid);
            if (user == null)
            {
                return false;
            }
            else
            {
                if (user.IsEnable == false)
                {
                    //登出 账号失效
                    await App.HttpContext.SignOutAsync(AuthorizeType.AdminAuthenticationScheme);
                    return false;//用户没启用，没有权限
                }
                await SetLoginAdminUserCache(user);
            }
            //return false;
        }
        else if (user.IsEnable == false)
        {
            //登出 账号失效
            await App.HttpContext.SignOutAsync(AuthorizeType.AdminAuthenticationScheme);
            return false;//用户没启用，没有权限
        }
        //administrator 与developer 不验证权限
        if (user.Account.ToLower().Trim() == "administrator".ToLower().Trim() || user.Account.ToLower().Trim() == "developer".ToLower().Trim())
        {
            return true;
        }
        if (user.Roles == null) return false;
        var menus = await GetMenusByUserId(user.Id);

        var isHasAuthorize = menus.Any(o => o.Controller != null && o.Actions != null && o.Controller.ToLower().Trim() == controller.Trim().ToLower() && o.Actions.ToLower().Trim().Contains(action.ToLower().Trim()));
        if (isHasAuthorize) return true;

        return false;
    }

    #endregion 管理用户登陆


    #region EmailSendConfig 邮箱发送配置

    /// <summary>
    /// 查询出指定邮箱的邮箱配置
    /// </summary>
    /// <param name="emailAccount">邮箱账号</param>
    /// <returns></returns>
    public async Task<SysEmailSendConfig> GetEmailSendConfig(string emailAccount)
    {
        var entities = await GetListAsync<SysEmailSendConfig>();
        return entities.FirstOrDefault(o => o.EmailAccount == emailAccount);
    }
    /// <summary>
    /// 查询出指定邮箱的邮箱配置
    /// </summary>
    /// <returns></returns>
    public async Task<SysEmailSendConfig> GetEmailSendConfig()
    {
        var entities = await GetListAsync<SysEmailSendConfig>();
        return entities.FirstOrDefault();
    }

    #endregion EmailSendConfig 邮箱发送配置

    #region EmailSendTemplate 邮件发送模板
    /// <summary>
    /// 根据模板类型查询一条，适合这个类型只有一个模板的情况
    /// </summary>
    /// <param name="emailSendTemplateType">模板类型</param>
    public async Task<SysEmailSendTemplate> GetEmailSendTemplate(EmailSendTemplateType emailSendTemplateType)
    {
        var entities = await GetListAsync<SysEmailSendTemplate>();
        return entities.FirstOrDefault(o => o.TemplateType == emailSendTemplateType);
    }
    #endregion
}